#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;

void mouseHandler(int event, int x, int y, int flafs, void* userData) {
    cv::Vec6i* pos = static_cast<cv::Vec6i*>(userData);
    if (event == cv::EVENT_LBUTTONDOWN) {
        pos->operator[](4) = 1;
        pos->operator[](5) = 0;
        pos->operator[](0) = x;
        pos->operator[](1) = y;
        pos->operator[](2) = -1;
        pos->operator[](3) = -1;
    }

    if (event == cv::EVENT_MOUSEMOVE && pos->operator[](4)) {
        pos->operator[](5) = 1;
        pos->operator[](2) = x;
        pos->operator[](3) = y;
    }
    if (event == cv::EVENT_LBUTTONUP ) {
        pos->operator[](4) = 0;
        pos->operator[](5) = 1;
        pos->operator[](2) = x;
        pos->operator[](3) = y;
    }
    
}


cv::Mat getHistImg (const vector<cv::MatND> hist) {
    int hist_w = 245, hist_h = 200;
    cv::Mat HistImg(hist_h, hist_w, CV_8UC3, cv::Scalar(0));
    for (int dim = 0; dim < 3; dim++) {
        cv::normalize(hist[dim], hist[dim], 0, hist_h * 0.9, cv::NORM_MINMAX);
        int histSize = hist[dim].rows;

        for (int i = 0; i < histSize; i++) {
            float binVal = hist[dim].at<float>(i);
            cv::rectangle(HistImg, cv::Point(dim * 80 + i*10, hist_h - binVal), 
            cv::Point(dim*80 + i * 10 + 10, hist_h), 
            cv::Scalar(dim == 0 ? 255 : 0 , dim == 1 ? 255 : 0, dim == 2 ? 255 : 0));
        }
    }
    return HistImg;
}

int main(int argc, char** argv) {
    if (argc < 2) {
        cout << "\nError: You had too few parameters.\n" << endl;
        return -1;
    }

    cv::Mat img = cv::imread(argv[1]);
    if (img.empty()) {
        cout << "Could not open " << argv[1] << endl;
        return 1;
    }

    cv::Point pos1, pos2;
    cv::Vec6i m_pos(-1, -1, -1, -1, 0, 0);
    cv::namedWindow("Image", cv::WINDOW_AUTOSIZE);
    cv::setMouseCallback("Image", mouseHandler, &m_pos);
    
    // a
    cv::Mat img_show;
    img.copyTo(img_show);

    // b
    cv::Mat histImg;
    vector<cv::Mat> planes;
    vector<cv::MatND> hist = {cv::MatND(), cv::MatND(), cv::MatND()};
    const int histSize[] = {8};
    float hranges[2] = {0, 255};
    const float* ranges[] = {hranges};

    while(1) {
        if (m_pos[5]) {
            img.copyTo(img_show);
            
            pos1.x = min(m_pos[0], m_pos[2]); pos1.y = min(m_pos[1], m_pos[3]);
            pos2.x = max(m_pos[0], m_pos[2]); pos2.y = max(m_pos[1], m_pos[3]);
            if (!m_pos[4]) {
                cv::Mat roi(img_show, cv::Range(pos1.y, pos2.y), cv::Range(pos1.x, pos2.x));

                cv::split(roi, planes);
                cv::calcHist(&planes[0], 1, 0, cv::Mat(), hist[0], 1, histSize, ranges);
                cv::calcHist(&planes[1], 1, 0, cv::Mat(), hist[1], 1, histSize, ranges);
                cv::calcHist(&planes[2], 1, 0, cv::Mat(), hist[2], 1, histSize, ranges);
                histImg = getHistImg(hist);
                roi *= 1.2;  // highlight
            }

            cv::rectangle(img_show, pos1, pos2, CV_RGB(255, 0, 0));
            m_pos[5] = 0;
        }
        cv::imshow("Image", img_show);
        if (histImg.data) 
            cv::imshow("Hist", histImg);
        if ((cv::waitKey(33) & 255) == 27)
            break;
    }
    
    // b 颜色直方图，各像素值的分布区间
    // calcHits

    cv::waitKey();
    return 0;
}


